package glemipsc;

import glemipsc.implementations.Argument;
import glemipsc.implementations.Implementation;
import glemipsc.implementations.Instruction;
import glemipsc.implementations.glemips32.Register;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class GLEMipsEmu {
	private Linker linker;
	private GLEMipsC.Environment env;
	private int[] memory = new int[4096];
	private int pc = 0, npc = 0;
	
	public void setLinker(Linker linker) {
		this.linker = linker;
	}
	public void setEnv(GLEMipsC.Environment env) {
		this.env = env;
	}
	
	public void emulate() {
		List<Instruction> instructions = new ArrayList<Instruction>();
		
		Iterator<Instruction> iter = linker.getBuiltInstructions().iterator();
		while (iter.hasNext()) {
			Instruction instr = iter.next();
			if (instr.isNop())
				continue;
			instructions.add(instr);
		}
		
		int ticks = 1;
		
		while (pc >= 0 && pc < instructions.size()) {
			Function fcnt = linker.getFunctionByAddress(pc);
			System.out.println(fcnt.getName() + ": " + pc);
			Instruction instr = instructions.get(pc);
			System.out.print(ticks++ + " :: " + instr.getAsmCode());
			npc = pc + 1;
			instr.emulate(this);
			if (fcnt.getName().equals("_start") && pc == fcnt.getStoreAddress().getValue() + fcnt.getCompiledInstructions().size() - 1)
				break;
			pc = npc;
			System.out.println();
		}
		
		System.out.println("---------------------------");
		
		Argument[] regs = GLEMipsC.compiler.getEnvironment().implementation.getRegisters();
		for (int i = 0; i < regs.length; i++) {
			System.out.println("R" + i + " = " + ((Register) regs[i]).getEmulValue());
		}
		System.out.println("---------------------------");
		for (int i = 0; i < memory.length; i++) {
			System.out.print(memory[i] + " ");
		}
		System.out.println();
	}
	
	public int load (int addr) {
		System.out.println("Address: " + addr);
		return memory[addr];
	}
	
	public void store (int addr, int value) {
		memory[addr] = value;
		System.out.println("Address: " + addr);
	}
	
	public int getPC() {
		return pc;
	}
	
	public void setPC(int value) {
		this.npc = value;
		System.out.println("set PC = " + value);
	}
	
	public Implementation getImplementation() {
		return env.implementation;
	}
}
